/*
 * Copyright (c) 2011 Daniel Loffgren.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY DANIEL LOFFGREN ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL DANIEL LOFFGREN BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define MAX_LINE_LEN	80	// We'll assume it's an 80 char xbm
#define	XPM_DELIMS		", \t"

static void usage() {
	printf("xbm2text [-c low_char] [-C high_char] -f file.xbm\n");
	exit(1);
}

int main (int argc, char * const argv[]) {
	FILE *file = NULL;
	int ch;
	char line[MAX_LINE_LEN + 1];
	char *buf;
	
	char byte = 0x00;
	
	long x = 0;
	long y = 0;
	short z = 0;
	long w = 0;
	long h = 0;
	
	char c = ' ';
	char C = '@';
	
	/* Parse args */	
	while ((ch = getopt(argc, argv, "f:c:C:")) != -1) {
		switch (ch) {
			case 'c': {
				c = *optarg;
			} break;
			case 'C': {
				C = *optarg;
			} break;
			case 'f': {
				file = fopen(optarg, "r");
				if (file == NULL) {
					fprintf(stderr, "xbm2text: %s: Could not open file for reading\n", optarg);
					exit(1);
				}
			} break;
			case '?':
			default:
				usage();
		}
	}

	if (file == NULL) {
		fprintf(stderr, "xbm2text: No file specified\n");
		usage();
	}
	
	/* Get width */
	buf = NULL;
	while (w == 0 && fgets(line, MAX_LINE_LEN, file)) {
		buf = strnstr(line, "width", MAX_LINE_LEN);
		if (buf) {
			buf += strlen("width");
			w = strtol(buf, NULL, 10);
		}
	}

	/* Get height */
	buf = NULL;
	while (h == 0 && fgets(line, MAX_LINE_LEN, file)) {
		buf = strnstr(line, "height", MAX_LINE_LEN);
		if (buf) {
			buf += strlen("height");
			h = strtol(buf, NULL, 10);
		}
	}
	
	if (w == 0 || h == 0) {
		fprintf(stderr, "xbm2text: %s: Bad file\n", optarg);
		exit(1);
	}
	
	/** printf("Image is %ldx%ld\n", w, h); */
	
	/* Parse XBM, outputting as we go */
	do {
		if (!fgets(line, MAX_LINE_LEN, file)) {
			*line = 0x00;
			fclose(file);
			file = NULL;
		}
		buf = strtok(line, XPM_DELIMS);
		while(buf) {
			if((strlen(buf) == 4) && !strncmp(buf, "0x", 2)) {
				/** printf("\n(%3ld, %3ld) of (%3ld, %3ld) HEX %s BIN ", x,y,w,h,buf);*/
				/* Read the byte */
				byte = (int)strtol(buf, NULL, 16);
				
				for (z = 0; z < 8; z++) {					
					/* Increment the pixel location */
					if(x < w) {
						x++;
					}
					else {
						printf("\n");
						x = 0;
						y++;
						break;
					}
					
					/* Print the bit */
					if ((byte >> z) & 1) {
						printf("%c", C);
					}
					else {
						printf("%c", c);						
					}					
				}
				if(z) {
					buf = strtok(NULL, XPM_DELIMS);
				}
			}
			else {
				buf = strtok(NULL, XPM_DELIMS);
			}
		}
	} while (file);
	
	fclose(file);
	
    return 0;
}
